package com.arpa.oms.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.arpa.core.utils.collection.CollectionUtil;
import com.arpa.core.web.Result;
import com.arpa.ntocc.common.common.Page;
import com.arpa.ntocc.common.common.cache.PartyCache;
import com.arpa.ntocc.common.common.constant.StrConsts;
import com.arpa.ntocc.common.common.exception.ServiceException;
import com.arpa.ntocc.common.common.util.UserUtil;
import com.arpa.ntocc.common.common.util.excel.EasyExcelUtil;
import com.arpa.ntocc.common.security.annotation.NeedLogin;
import com.arpa.oms.common.util.DataMaskingUtils;
import com.arpa.oms.domain.dto.*;
import com.arpa.oms.domain.entity.Sale;
import com.arpa.oms.domain.entity.SaleItem;
import com.arpa.oms.domain.enums.OrderStatusEnum;
import com.arpa.oms.domain.vo.OmsSaleExcelVO;
import com.arpa.oms.domain.vo.OmsSaleReturnVO;
import com.arpa.oms.domain.vo.SaleItemVO;
import com.arpa.oms.domain.vo.SaleVO;
import com.arpa.oms.service.IOrderDealService;
import com.arpa.oms.service.ISaleItemService;
import com.arpa.oms.service.ISaleService;
import com.arpa.wms.domain.entity.Receive;
import com.arpa.wms.domain.vo.ReceiveVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import io.micrometer.core.instrument.util.JsonUtils;
import io.swagger.annotations.*;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.Future;
import java.util.stream.Collectors;


/**
 * <p>
 * OMS销售单 Controller
 * </p>
 *
 * @author LEO
 * @since 2020-10-23
 */
@Api(tags = "OMS销售单")
@RestController
@RequestMapping(value="/oms/sale", produces = "application/json;charset=UTF-8")
@Log4j2(topic = "business")
public class SaleController {

    private final ISaleService iSaleService;
    private final ISaleItemService iSaleItemService;
    private final IOrderDealService iOrderDealService;
    private final PartyCache partyCache;
    @Resource
    public RedissonClient redissonClient;

    public SaleController(ISaleService iSaleService, ISaleItemService iSaleItemService, IOrderDealService iOrderDealService, PartyCache partyCache) {
        this.iSaleService = iSaleService;
        this.iSaleItemService = iSaleItemService;
        this.iOrderDealService = iOrderDealService;
        this.partyCache = partyCache;
    }

    /**
     * OMS销售单列表
     *
     * @param dto
     * @param request
     * @return
     */
    @ApiOperation(value = "OMS销售单列表", notes = "OMS销售单列表接口")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer "),
        @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @ApiResponses(@ApiResponse(code = 0, message = "success", response = ReceiveVO.class))
    @NeedLogin
    @GetMapping()
    public Result list(SaleDto dto, HttpServletRequest request) {
        try {
            dto.setGroupCode(UserUtil.getBranchCode());
            dto.setShipmentCode(UserUtil.getLoginWarehouseCodeOrShipmentCode());
            dto.setWarehouseCodes(UserUtil.getShipmentAuthorizeWarehouseCodes());

            SaleVO saleVo = iSaleService.queryListSum(dto);
            List<SaleVO> saleVOS = iSaleService.queryList(dto);
            Page returnPage = new Page(dto.getPageNum(),dto.getPageSize());
            returnPage.setRecords(saleVOS);
            returnPage.setTotal(saleVo.getTotal());
            returnPage.setSumObject(saleVo);
            return Result.ok().data(returnPage);
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE,e);
            return Result.error(e.getMessage());
        }
    }

    /**
     * 添加 销售单
     *
     * @param sale
     * @param request
     * @return
     */
    @ApiOperation(value = "添加 销售单 ", notes = "添加 销售单")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer 123456"),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @NeedLogin
    @PostMapping()
    public Result create(@RequestBody @Validated(Sale.Save.class) Sale sale, HttpServletRequest request) {
        try {

            if(IterUtil.isEmpty(sale.getSaleItemList())){
                return Result.error("新增销售单失败，销售商品列表为空！");
            }
            sale.setShipmentCode(UserUtil.getShipmentCompanyCode());
            sale.setShipmentName(UserUtil.getShipmentCompanyName());
            iSaleService.localSave(sale);
            return Result.ok("添加成功");
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE,e);
            return Result.error(e.getMessage());
        }
    }

    /**
     * 保存销售单
     *
     * @param sale 销售单
     * @param request
     * @return
     */
    @ApiOperation(value = "保存销售单 ", notes = "保存销售单")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer 123456"),
        @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @NeedLogin
    @PutMapping()
    public Result save(@RequestBody @Validated(Sale.Update.class) Sale sale,  HttpServletRequest request) {
        if(StringUtils.isBlank(sale.getCode())){
            return Result.error("code不能为空");
        }
        sale.setShipmentCode(UserUtil.getShipmentCompanyCode());
        sale.setShipmentName(UserUtil.getShipmentCompanyName());

        int updateNum = iSaleService.updateByCode(sale);
        if(updateNum == 0){
            return Result.error("没有更新数据！code:"+sale.getCode());
        }else{
            return Result.ok("成功,更新"+updateNum+"条数据！");
        }
    }

    /**
     * 提交销售单
     *
     * @param entity 销售单
     * @param request
     * @return
     */
    @ApiOperation(value = "提交销售单 ", notes = "提交销售单")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer 123456"),
        @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @NeedLogin
    @PostMapping("/submit")
    public Result submit(@RequestBody @Validated(Sale.Save.class) Sale entity, HttpServletRequest request) {
        try {
            if(IterUtil.isEmpty(entity.getSaleItemList())){
                return Result.error("新增销售单失败，采购商品为空！");
            }
            entity.setShipmentCode(UserUtil.getShipmentCompanyCode());
            entity.setShipmentName(UserUtil.getShipmentCompanyName());
            iSaleService.submit(entity);
            return Result.ok("添加成功");
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE,e);
            return Result.error(e.getMessage());
        }
    }

    /**
    * 销售单详情
    *
    * @param code
    * @param request
    * @return
    */
    @ApiOperation(value = "销售单详情", notes = "销售单详情")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer 123456"),
        @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000"),
        @ApiImplicitParam(name = "code", value = "销售单号", paramType = "path", dataType = "String")
    })
    @ApiResponses(@ApiResponse(code = 0, message = "success", response = Receive.class))
    @NeedLogin
    @GetMapping(value = "/{code}")
    public Result receive(@PathVariable String code, HttpServletRequest request) {
        try {
            SaleVO saleVo = iSaleService.getByCode(code);
            return Result.ok().data(saleVo);
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE,e);
            return Result.error(e.getMessage());
        }
    }




    /**
     * 作废销售单
     *
     * @param code
     * @param request
     * @return
     */
    @ApiOperation(value = "作废销售单", notes = "作废销售单")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer 123456"),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000"),
            @ApiImplicitParam(name = "code", value = "销售单号", paramType = "path", dataType = "String")
    })
    @ApiResponses(@ApiResponse(code = 0, message = "success", response = Receive.class))
    @NeedLogin
    @GetMapping(value = "/annul/{code}")
    public Result getReceive(@PathVariable String code, HttpServletRequest request) {
        try {
            iSaleService.annul(code);
            return Result.ok("作废成功");
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE,e);
            return Result.error(e.getMessage());
        }
    }

    /**
     * 审核销售单
     * @param entity
     * @param request
     * @return
     */
    @ApiOperation(value = "审核 销售单", notes = "审核 销售单")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer "),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @NeedLogin
    @PutMapping(value = "/audit")
    public Result audit(OmsAuditSaleDTO entity, HttpServletRequest request) {
        if(CollectionUtil.isEmpty(entity.getSaleCodes())){
            return Result.error("审核记录不能为空");
        }
        if (!StrUtil.equalsAny(entity.getStatus(), OrderStatusEnum.NO_PASS.getValue(), OrderStatusEnum.PASS.getValue())){
            throw new ServiceException("审核状态不正确");
        }
        // 获取数据库数据
        List<Sale> saleList = iSaleService.list(new QueryWrapper<Sale>().lambda().in(Sale::getCode, entity.getSaleCodes()));
        // 判断审核状态
        if(OrderStatusEnum.NO_PASS.getValue().equals(entity.getStatus())){
            // 审核未通过，判断审核意见是否填写
            if(StrUtil.isBlank(entity.getVerifyOpinion())){
                throw new ServiceException("审核意见不能为空。");
            }
            // 释放被锁的库存
            iSaleService.releaseUseQuantity(entity.getSaleCodes());

            saleList.forEach(sale -> {
                sale.setVerifyBy(UserUtil.getCode());
                sale.setVerifyName(partyCache.translate(UserUtil.getCode()));
                sale.setVerifyOpinion(entity.getVerifyOpinion());
                sale.setGmtVerify(LocalDateTime.now());
                sale.setStatus(OrderStatusEnum.NO_PASS.getValue());
                sale.setModifiedBy(sale.getVerifyBy());
                sale.setModifiedName(sale.getVerifyName());
            });
            iSaleService.updateBatchById(saleList);
            return Result.ok("操作完成");
        }
        //获取没有快递或者没有仓库的销售单
        List<Sale> saleWithoutCarrierNameList = saleList.stream().filter(e -> StrUtil.isEmpty(e.getCarrierName()) || StrUtil.isEmpty(e.getWarehouseCode())).collect(Collectors.toList());
        if (IterUtil.isNotEmpty(saleWithoutCarrierNameList)) {
            List<String> saleCodesWithoutCarrierName = saleWithoutCarrierNameList.stream().map(info -> info.getCode()).collect(Collectors.toList());
            throw new ServiceException("销售单[ "+ saleCodesWithoutCarrierName + " ]没有快递或者仓库信息，请确认");
        }
        //查询商品为空的销售单号
        List<String> saleGoodsLackGoodsInfo = iSaleItemService.getSaleCodelackGoodsInfo(entity.getSaleCodes());
        if (IterUtil.isNotEmpty(saleGoodsLackGoodsInfo)) {
            throw new ServiceException("销售单[ "+ saleGoodsLackGoodsInfo + " ]缺少商品信息，请确认");
        }
        if (CollectionUtil.isEmpty(saleList)) {
            throw new ServiceException("单据不存在");
        }
        // 校验数据库数据状态
        List<Sale> checkList = saleList.stream().filter(v -> ObjectUtil.notEqual(v.getStatus(), OrderStatusEnum.PENDING.getValue()) && ObjectUtil.notEqual(v.getStatus(), OrderStatusEnum.WMS_ERROR.getValue())).collect(Collectors.toList());
        if(CollectionUtil.isNotEmpty(checkList)){
            throw new ServiceException("单据【" + checkList.get(0).getCode() + "】不是待审核状态，无法审核。");
        }
        List<RLock> locks = Lists.newArrayList();
        List<Map<String, String>> failCodes = Lists.newArrayList();
        StringBuilder failMsg = new StringBuilder();
        try {
            //可操作的CODE
            List<Sale> execCodes = Lists.newArrayList();
            //合单
            List<Sale> mergeList = iOrderDealService.merge(saleList);
            Map<String, Sale> saleMap = mergeList.stream().collect(Collectors.toMap(Sale::getCode, v -> v));
            for (Sale sale : mergeList) {
                RLock l = redissonClient.getLock(getAssignLockKey(sale.getCode()));
                if (l.tryLock()) {
                    log.info("任务【{}】获得锁", sale.getCode());
                    execCodes.add(sale);
                    locks.add(l);
                } else {
                    Map<String, String> map = new HashMap<>();
                    map.put("key", sale.getCode());
                    map.put("message", "任务操作中");
                    failCodes.add(map);
                    failMsg.append("任务【").append(sale.getCode()).append("】正在操作中</br>");
                    log.error("任务【{}】正在操作中", sale.getCode());
                }
            }
            // 失败的订单集合
            // 线程结果集
            Map<String, Future<Boolean>> futureMap = Maps.newHashMap();
            for (Sale sale : execCodes) {
                Future<Boolean> future = iSaleService.audit(sale, entity.getStatus(), entity.getVerifyOpinion());
                if (future == null) {
                    Map<String, String> map = new HashMap<>();
                    map.put("key", sale.getCode());
                    map.put("message", "操作失败");
                    failCodes.add(map);
                } else {
                    futureMap.put(sale.getCode(), future);
                }
            }
            futureMap.forEach((key, future) -> {
                try {
                    while (true) {
                        if (future.isDone()) {
                            Boolean status = future.get();
                            if (!status) {
                                Map<String, String> map = new HashMap<>();
                                map.put("key", key);
                                map.put("message", "操作失败");
                                failCodes.add(map);
                            }
                            break;
                        }
                    }
                } catch (ServiceException e) {
                    log.error("oms订单推送到wms【{}】线程获取结果【{}】", key, e.getMessage());
                    Map<String, String> map = new HashMap<>();
                    map.put("key", key);
                    map.put("message", e.getMessage());
                    failCodes.add(map);
                } catch (Exception e) {
                    log.error("oms订单推送到wms【{}】线程获取结果【{}】", key, e.getMessage());
                    Map<String, String> map = new HashMap<>();
                    map.put("key", key);
                    map.put("message", e.getMessage());
                    failCodes.add(map);
                }
            });
            List<Sale> resultData = new ArrayList<>();
            for (Map.Entry<String, Future<Boolean>> map : futureMap.entrySet()) {
                Sale sale = saleMap.get(map.getKey());
                //处理合单
                if(StringUtils.isNotBlank(sale.getMergeCode())) {
                    List<Sale> mergeSaleList = saleList.stream().filter(v -> StringUtils.isNotBlank(v.getMergeCode()) && v.getMergeCode().equals(sale.getMergeCode())).collect(Collectors.toList());
                    if (IterUtil.isNotEmpty(mergeSaleList)) {
                        mergeSaleList.forEach(m -> {
                            m.setStatus(OrderStatusEnum.PASS.getValue());
                            m.setWmsMessage("success");
                            m.setVerifyBy(UserUtil.getCode());
                            m.setVerifyName(partyCache.translate(UserUtil.getCode()));
                            m.setVerifyOpinion(entity.getVerifyOpinion());
                            m.setGmtVerify(LocalDateTime.now());
                            m.setModifiedBy(sale.getVerifyBy());
                            m.setModifiedName(sale.getVerifyName());

                        });
                        resultData.addAll(mergeSaleList);
                    } else {
                        sale.setStatus(OrderStatusEnum.PASS.getValue());
                        sale.setWmsMessage("success");
                        sale.setVerifyBy(UserUtil.getCode());
                        sale.setVerifyName(partyCache.translate(UserUtil.getCode()));
                        sale.setVerifyOpinion(entity.getVerifyOpinion());
                        sale.setGmtVerify(LocalDateTime.now());
                        sale.setModifiedBy(sale.getVerifyBy());
                        sale.setModifiedName(sale.getVerifyName());
                        resultData.add(sale);
                    }
                } else {
                    sale.setStatus(OrderStatusEnum.PASS.getValue());
                    sale.setWmsMessage("success");
                    sale.setVerifyBy(UserUtil.getCode());
                    sale.setVerifyName(partyCache.translate(UserUtil.getCode()));
                    sale.setVerifyOpinion(entity.getVerifyOpinion());
                    sale.setGmtVerify(LocalDateTime.now());
                    sale.setModifiedBy(sale.getVerifyBy());
                    sale.setModifiedName(sale.getVerifyName());
                    resultData.add(sale);
                }
            }
            for (Map<String, String> map : failCodes) {
                Sale sale = saleMap.get(map.get("key"));
                //处理合单
                if(StringUtils.isNotBlank(sale.getMergeCode())) {
                    List<Sale> mergeSaleList = saleList.stream().filter(v -> StringUtils.isNotBlank(v.getMergeCode()) && v.getMergeCode().equals(sale.getMergeCode())).collect(Collectors.toList());
                    if (IterUtil.isNotEmpty(mergeSaleList)) {
                        mergeSaleList.forEach(m -> {
                            m.setStatus(OrderStatusEnum.WMS_ERROR.getValue());
                            String errorInfo = map.get("message");
                            sale.setWmsMessage(StringUtils.isNotEmpty(errorInfo) ? errorInfo.replace("com.arpa.ntocc.common.common.exception.ServiceException:", ""): "");
                            m.setVerifyBy(UserUtil.getCode());
                            m.setVerifyName(partyCache.translate(UserUtil.getCode()));
                            m.setVerifyOpinion(entity.getVerifyOpinion());
                            m.setGmtVerify(LocalDateTime.now());
                            m.setModifiedBy(sale.getVerifyBy());
                            m.setModifiedName(sale.getVerifyName());
                            resultData.add(sale);
                        });
                        resultData.addAll(mergeSaleList);
                    } else {
                        sale.setStatus(OrderStatusEnum.WMS_ERROR.getValue());
                        String errorInfo = map.get("message");
                        sale.setWmsMessage(StringUtils.isNotEmpty(errorInfo) ? errorInfo.replace("com.arpa.ntocc.common.common.exception.ServiceException:", ""): "");
                        sale.setVerifyBy(UserUtil.getCode());
                        sale.setVerifyName(partyCache.translate(UserUtil.getCode()));
                        sale.setVerifyOpinion(entity.getVerifyOpinion());
                        sale.setGmtVerify(LocalDateTime.now());
                        sale.setModifiedBy(sale.getVerifyBy());
                        sale.setModifiedName(sale.getVerifyName());
                        resultData.add(sale);
                    }
                } else {
                    sale.setStatus(OrderStatusEnum.WMS_ERROR.getValue());
                    String errorInfo = map.get("message");
                    sale.setWmsMessage(StringUtils.isNotEmpty(errorInfo) ? errorInfo.replace("com.arpa.ntocc.common.common.exception.ServiceException:", ""):"");
                    sale.setVerifyBy(UserUtil.getCode());
                    sale.setVerifyName(partyCache.translate(UserUtil.getCode()));
                    sale.setVerifyOpinion(entity.getVerifyOpinion());
                    sale.setGmtVerify(LocalDateTime.now());
                    sale.setModifiedBy(sale.getVerifyBy());
                    sale.setModifiedName(sale.getVerifyName());
                    resultData.add(sale);
                }
            }
            if (CollectionUtil.isNotEmpty(resultData)) {
                iSaleService.updateBatchById(resultData);
            }
        } finally {
            try {
                locks.forEach(l -> {
                    // 判断锁不为空 && 当前线程获得到了锁
                    if (null != l && l.isLocked()) {
                        l.unlock();
                    }
                });
            } catch (Exception e) {
                log.error("释放锁失败！！", e);
            }

        }
        return Result.ok("操作完成");
    }


    /**
     * 获取可退货销售订单
     * 根据仓库、入驻商、客户， 出库数量-已退数量>0  查询销售单
     * @param dto
     * @param request
     * @return
     */
    @ApiOperation(value = "获取可退货 销售单", notes = "获取可退货 销售单")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer "),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @NeedLogin
    @GetMapping(value = "/findCanRefundList")
    public Result findCanRefundList(SaleDto dto, HttpServletRequest request) {
        try {
            dto.setShipmentCode(UserUtil.getShipmentCompanyCode());
            dto.setShipmentName(UserUtil.getShipmentCompanyName());
            // 根据仓库、入驻商、客户、已发数量>退货数量 获取销售单
            List<Sale> sales = iSaleService.findCanRefundList(dto);

            return Result.ok().data(sales);
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE,e);
            return Result.error(e.getMessage());
        }
    }

    /**
     * 获取可退货销售单明细
     * 根据仓库、入驻商、客户， 出库数量-已退数量>0  查询销售单
     * @param dto
     * @param request
     * @return
     */
    @ApiOperation(value = "获取可退货 销售单明细", notes = "获取可退货 销售单明细")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer "),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @NeedLogin
    @GetMapping(value = "/findCanRefundItemList")
    public Result findCanRefundItemList(SaleItemDto dto, HttpServletRequest request) {
        try {
            // 根据仓库、入驻商、客户、已发数量>退货数量 获取销售单
            List<SaleItemVO> saleItems = iSaleService.findCanRefundItemList(dto);

            return Result.ok().data(saleItems);
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE,e);
            return Result.error(e.getMessage());
        }
    }

    /**
     * 获取 OMS销售单 审核列表
     *
     * @param dto
     * @param request
     * @return
     */
    @ApiOperation(value = "获取 OMS销售单 审核列表", notes = "获取 OMS销售单 审核列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer "),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @ApiResponses(@ApiResponse(code = 0, message = "success", response = OmsSaleReturnVO.class))
    @NeedLogin
    @GetMapping("/auditList")
    public Result auditList(SaleDto dto, HttpServletRequest request) {
        try {
            dto.setGroupCode(UserUtil.getBranchCode());
            dto.setShipmentCode(UserUtil.getLoginWarehouseCodeOrShipmentCode());
            dto.setWarehouseCodes(UserUtil.getShipmentAuthorizeWarehouseCodes());

            // 前端传的审核状态为空的话，则只查询“待审核”、“审核不通过”、“审核通过”的数据
            if (StrUtil.isBlank(dto.getAuditStatus())) {
                List<String> auditStatus = Arrays.asList(OrderStatusEnum.PENDING.getValue(), OrderStatusEnum.NO_PASS.getValue(), OrderStatusEnum.PASS.getValue(), OrderStatusEnum.WMS_ERROR.getValue());
                String auditStatusStr = auditStatus.stream().map(c -> StrUtil.wrap(c, "'")).collect(Collectors.joining(","));
                dto.setAuditStatus(auditStatusStr);
            }

            SaleVO saleVo = iSaleService.queryListSum(dto);
            List<SaleVO> saleVOS = iSaleService.queryList(dto);

            Page returnPage = new Page(dto.getPageNum(),dto.getPageSize());
            returnPage.setRecords(saleVOS);
            returnPage.setTotal(saleVo.getTotal());
            returnPage.setSumObject(saleVo);
            return Result.ok().data(returnPage);
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE,e);
            return Result.error(e.getMessage());
        }
    }

    /**
     * 销售单审核-批量添加商品
     *
     * @param dto
     * @param request
     * @return
     */
    @ApiOperation(value = "销售单审核-批量添加商品", notes = "销售单审核-批量添加商品")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer "),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @ApiResponses(@ApiResponse(code = 0, message = "success", response = OmsSaleReturnVO.class))
    @NeedLogin
    @PostMapping("/batchAddGoods")
    public Result batchAddGoods(@RequestBody BatchAddGoodsDTO dto, HttpServletRequest request) {
        try {
            return iSaleItemService.batchAddGoods(dto);
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE,e);
            return Result.error(e.getMessage());
        }
    }

    /**
     *OMS销售单 合并
     *
     * @param codes
     * @return
     */
    @ApiOperation(value = "OMS销售单合并", notes = "OMS销售单合并")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer "),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @NeedLogin
    @PutMapping("/merge")
    public Result merge(@RequestParam List<String> codes) {
        if (CollectionUtil.isEmpty(codes)) {
            return Result.error("无可合并订单");
        }
        Integer num = iSaleService.merge(codes);
        return Result.ok("共有" + num + "订单被合并");
    }

    @ApiOperation(value = "OMS销售单审核退回", notes = "OMS销售单审核退回")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer "),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @NeedLogin
    @PutMapping("/back")
    public Result back(@RequestParam List<String> codes) {
        if (CollectionUtil.isEmpty(codes)) {
            return Result.error("无可退回订单");
        }
        boolean flag = iSaleService.back(codes);
        return flag ? Result.ok() : Result.error();
    }

    @ApiOperation(value = "销售单 导入 预览", notes = "销售单 导入 预览")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer "),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000"),
            @ApiImplicitParam(name = "filePath", value = "文件路径", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "isView", value = "是否已经预览", required = true, paramType = "query", dataType = "Integer")
    })
    @PostMapping("/saleExcelView")
    public Result goodsView(String filePath, Integer isView, HttpServletRequest request) {
        try {

            java.net.URL url = new java.net.URL(filePath);
            List<OmsSaleExcelDTO> list = EasyExcelUtil.read(url.openStream(), OmsSaleExcelDTO.class,2);
            if(CollUtil.isEmpty(list)) {
                throw new ServiceException("文件内容为空");
            }
            List<OmsSaleExcelVO> saleExcelVOS = iSaleService.saleExcelView(list);
            return new Result().data(saleExcelVOS);
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE,e);
            return Result.error(e.getMessage());
        }
    }

    @ApiOperation(value = "销售单 导入", notes = "销售单 导入")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer "),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000"),
            @ApiImplicitParam(name = "filePath", value = "文件路径", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "isView", value = "是否已经预览", required = true, paramType = "query", dataType = "Integer")
    })
    @PostMapping("/saleImport")
    public Result goodsRelationImport(@RequestParam("importCode") String importCode, HttpServletRequest request) {
        try {
            Result result = iSaleService.importSale(importCode);
            return result;
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE,e);
            return Result.error(e.getMessage());
        }
    }

    @ApiOperation(value = "自动审核销售单", notes = "自动审核销售单")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer "),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @PostMapping("/autoAudit")
    public Result autoAudit(@RequestBody List<Sale> sales) {
        log.info("自动审核入参为{}", sales);
        try {
            List<String> codesOfAutoAudit = Lists.newArrayList();
            //1.判断订单是否符合自动审核规则
            sales.stream().forEach(sale -> {
                if (iSaleService.validateIsAutoAudit(sale)) {
                    codesOfAutoAudit.add(sale.getCode());
                }
            });
            if (IterUtil.isEmpty(codesOfAutoAudit)) {
                log.info("没有符合自动审核的订单");
                return Result.ok("没有符合自动审核的订单");
            }
            //2.如符合，进行审核确认
            OmsAuditSaleDTO entity = new OmsAuditSaleDTO();
            entity.setStatus(OrderStatusEnum.PASS.getValue());
            entity.setSaleCodes(codesOfAutoAudit);
            // 获取数据库数据
            List<Sale> saleList = iSaleService.list(new QueryWrapper<Sale>().lambda().in(Sale::getCode, entity.getSaleCodes()));
            //获取没有快递或者没有仓库的销售单
            List<Sale> saleWithoutCarrierNameList = saleList.stream().filter(e -> StrUtil.isEmpty(e.getCarrierName()) || StrUtil.isEmpty(e.getWarehouseCode())).collect(Collectors.toList());
            if (IterUtil.isNotEmpty(saleWithoutCarrierNameList)) {
                List<String> saleCodesWithoutCarrierName = saleWithoutCarrierNameList.stream().map(info -> info.getCode()).collect(Collectors.toList());
                log.error("销售单[ "+ saleCodesWithoutCarrierName + " ]没有快递或者仓库信息，请确认");
                throw new ServiceException("销售单[ "+ saleCodesWithoutCarrierName + " ]没有快递或者仓库信息，请确认");
            }
            if (CollectionUtil.isEmpty(saleList)) {
                throw new ServiceException("单据不存在");
            }
            // 校验数据库数据状态
            List<Sale> checkList = saleList.stream().filter(v -> ObjectUtil.notEqual(v.getStatus(), OrderStatusEnum.PENDING.getValue()) && ObjectUtil.notEqual(v.getStatus(), OrderStatusEnum.WMS_ERROR.getValue())).collect(Collectors.toList());
            if(CollectionUtil.isNotEmpty(checkList)){
                log.error("单据【" + checkList.get(0).getCode() + "】不是待审核状态，无法审核。");
                throw new ServiceException("单据【" + checkList.get(0).getCode() + "】不是待审核状态，无法审核。");
            }
            List<RLock> locks = Lists.newArrayList();
            List<Map<String, String>> failCodes = Lists.newArrayList();
            StringBuilder failMsg = new StringBuilder();
            try {
                //可操作的CODE
                List<Sale> execCodes = Lists.newArrayList();
                //合单
                List<Sale> mergeList = iOrderDealService.merge(saleList);
                Map<String, Sale> saleMap = mergeList.stream().collect(Collectors.toMap(Sale::getCode, v -> v));
                for (Sale sale : mergeList) {
                    RLock l = redissonClient.getLock(getAssignLockKey(sale.getCode()));
                    if (l.tryLock()) {
                        log.info("任务【{}】获得锁", sale.getCode());
                        execCodes.add(sale);
                        locks.add(l);
                    } else {
                        Map<String, String> map = new HashMap<>();
                        map.put("key", sale.getCode());
                        map.put("message", "任务操作中");
                        failCodes.add(map);
                        failMsg.append("任务【").append(sale.getCode()).append("】正在操作中</br>");
                        log.error("任务【{}】正在操作中", sale.getCode());
                    }
                }
                // 失败的订单集合
                // 线程结果集
                Map<String, Future<Boolean>> futureMap = Maps.newHashMap();
                for (Sale sale : execCodes) {
                    Future<Boolean> future = iSaleService.audit(sale, entity.getStatus(), entity.getVerifyOpinion());
                    if (future == null) {
                        Map<String, String> map = new HashMap<>();
                        map.put("key", sale.getCode());
                        map.put("message", "操作失败");
                        failCodes.add(map);
                    } else {
                        futureMap.put(sale.getCode(), future);
                    }
                }
                futureMap.forEach((key, future) -> {
                    try {
                        while (true) {
                            if (future.isDone()) {
                                Boolean status = future.get();
                                if (!status) {
                                    Map<String, String> map = new HashMap<>();
                                    map.put("key", key);
                                    map.put("message", "操作失败");
                                    failCodes.add(map);
                                }
                                break;
                            }
                        }
                    } catch (ServiceException e) {
                        log.error("oms订单推送到wms【{}】线程获取结果【{}】", key, e.getMessage());
                        Map<String, String> map = new HashMap<>();
                        map.put("key", key);
                        map.put("message", e.getMessage());
                        failCodes.add(map);
                    } catch (Exception e) {
                        log.error("oms订单推送到wms【{}】线程获取结果【{}】", key, e.getMessage());
                        Map<String, String> map = new HashMap<>();
                        map.put("key", key);
                        map.put("message", e.getMessage());
                        failCodes.add(map);
                    }
                });
                List<Sale> resultData = new ArrayList<>();
                for (Map<String, String> map : failCodes) {
                    Sale sale = saleMap.get(map.get("key"));
                    sale.setStatus(OrderStatusEnum.WMS_ERROR.getValue());
                    sale.setWmsMessage(map.get("message"));
                    resultData.add(sale);
                }
                for (Map.Entry<String, Future<Boolean>> map : futureMap.entrySet()) {
                    Sale sale = saleMap.get(map.getKey());
                    sale.setStatus(OrderStatusEnum.PASS.getValue());
                    sale.setWmsMessage("success");
                    resultData.add(sale);
                }
                if (CollectionUtil.isNotEmpty(resultData)) {
                    iSaleService.updateBatchById(resultData);
                }
            } finally {
                try {
                    locks.forEach(l -> {
                        // 判断锁不为空 && 当前线程获得到了锁
                        if (null != l && l.isLocked()) {
                            l.unlock();
                        }
                    });
                } catch (Exception e) {
                    log.error("释放锁失败！！", e);
                }
            }
            return Result.ok();
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE,e);
            return Result.error(e.getMessage());
        }
    }

    /**
     * 保存备注信息
     *
     * @param entity 销售单
     * @param request
     * @return
     */
    @ApiOperation(value = "保存备注信息 ", notes = "保存备注信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer 123456"),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @NeedLogin
    @PostMapping("/saveRemark")
    public Result saveRemark(@RequestBody Sale entity, HttpServletRequest request) {
        try {
            iSaleService.updateSaleByCode(entity);
            return Result.ok("添加成功");
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE,e);
            return Result.error(e.getMessage());
        }
    }

    /**
     * 保存客户信息
     *
     * @param entity 销售单
     * @param request
     * @return
     */
    @ApiOperation(value = "保存客户信息 ", notes = "保存客户信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer 123456"),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @NeedLogin
    @PostMapping("/saveCustomerInfo")
    public Result saveCustomerInfo(@RequestBody Sale entity, HttpServletRequest request) {
        try {
            iSaleService.updateSaleByCode(entity);
            return Result.ok("添加成功");
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE,e);
            return Result.error(e.getMessage());
        }
    }

    /**
     * 保存订单明细
     *
     * @param entity 销售单
     * @param request
     * @return
     */
    @ApiOperation(value = "保存订单明细 ", notes = "保存订单明细")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer 123456"),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @NeedLogin
    @PostMapping("/saveSaleItem")
    public Result saveSaleItem(@RequestBody Sale entity, HttpServletRequest request) {
        try {
            iSaleService.updateSaleItem(entity);
            return Result.ok("添加成功");
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE,e);
            return Result.error(e.getMessage());
        }
    }
    /**
     * 任务指派分布式锁
     *
     * @param code
     * @return
     */
    private String getAssignLockKey(String code) {
        return String.format("oms-order-code-%s", code);
    }
}
